﻿using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using Microsoft.WowAddonStudio.FrameXml.Serialization;

namespace Microsoft.WowAddonStudio.FrameXml.Components.Actions
{
    public abstract class Action
    {
        private readonly IFrameXmlControl control;

        /// <summary>
        /// Initializes a new instance of the <see cref="Action"/> class.
        /// </summary>
        protected Action(IFrameXmlControl control)
        {
            if (control == null)
                throw new ArgumentNullException("control");

            this.control = control;
        }

        /// <summary>
        /// Returns an object that represents a service provided by the FrameXML control.
        /// </summary>
        /// <typeparam name="TService">The type of the service.</typeparam>
        /// <returns>An instance of the <typeparamref name="TService"/> class.</returns>
        public TService GetService<TService>() where TService : class
        {
            if (control.Site != null)
                return (TService)control.Site.GetService(typeof(TService));

            return null;
        }

        /// <summary>
        /// Gets the control associated with the action.
        /// </summary>
        protected IFrameXmlControl Control
        {
            get { return control; }
        }

        /// <summary>
        /// Gets the underlying serialization object of the control associated with the action.
        /// </summary>
        protected SerializationObject SerializationObject
        {
            get { return control.SerializationObject; }
        }

        /// <summary>
        /// Gets a value indicating whether this action is available.
        /// </summary>
        public virtual bool IsAvailable
        {
            get { return true; }
        }

        /// <summary>
        /// Gets or sets the name of the action.
        /// </summary>
        public virtual string DisplayName
        {
            get { return this.GetType().Name; }
        }

        /// <summary>
        /// Gets or sets the category of the action.
        /// </summary>
        public string Category { get; set; }

        /// <summary>
        /// Gets or sets the description of the action.
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// Invokes the action.
        /// </summary>
        public abstract void Invoke();

        /// <summary>
        /// Notifies the component change service of a change.
        /// </summary>
        /// <param name="member">The member that has changed.</param>
        /// <param name="oldValue">The old value.</param>
        /// <param name="newValue">The new value.</param>
        protected void RaiseComponentChanged(MemberDescriptor member, object oldValue, object newValue)
        {
            var componentChangeService = this.GetService<IComponentChangeService>();
            if (componentChangeService != null)
                componentChangeService.OnComponentChanged(this.Control, member, oldValue, newValue);
        }
    }
}
